//-------------------------------------------------------------------
//	Copyright (c) 2010-2012 Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_CL_MEMORY_H
#define _UX_CL_MEMORY_H

#include "CLDevice.h"
#include "CLEvent.h"
#include "CLQueue.h"

namespace Engine
{
namespace CLSystems
{

	//
	// CL Memory Object
	//

	class _EXPORT_ CLMemory : public CLBaseObject
	{
	protected:
		cl_mem		_pMemory;
		
	protected:
		virtual void _RetainRef()	const;
		virtual void _ReleaseRef()	const;
		virtual uint _GetRefCount()	const;
		virtual void _Destroy();

	public:
		CLMemory();
		~CLMemory();

		bool EnqueueUnmap(CLQueue *pQueue, void *pPtr, const cl_event_array_t &aEvents = cl_event_array_t(),
							CLEvent **pEvent = nullptr);

		bool GetGLObject(cl_gl_object::type &eType, GLuint &uIdent);

		virtual void Destroy();

		cl_mem	GetIdent() const	{ return _pMemory; }
	};



	//
	// CL Buffer
	//

	class _EXPORT_ CLBuffer : public CLMemory
	{
	public:
		CLBuffer();
		~CLBuffer();
		
		bool Create(usize uSize, cl_memory::type eFlags, void *pBuf = nullptr);
		bool Create(GLuint uBuffer, cl_memory::type eFlags);

		bool EnqueueRead(CLQueue *pQueue, bool bASync, usize uOffset, usize uDataSize, void *pData,
							const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueRead(CLQueue *pQueue, bool bASync, const svec3 &vBufOffset, const svec3 &vDataOffset,
							const svec3 &vDataSize, const svec2 &vBufRowSlicePitch,
							const svec2 &vDataRowSlicePitch, void *pData,
							const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, usize uOffset, usize uDataSize, const void *pData,
							const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, const svec3 &vBufOffset, const svec3 &vDataOffset,
							const svec3 &vDataSize, const svec2 &vBufRowSlicePitch,
							const svec2 &vDataRowSlicePitch, const void *pData,
							const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueMap(void *&pResult, CLQueue *pQueue, bool bASync, e_rw_mode::type eRW, usize uOffset, usize uSize,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);
	};



	//
	// CL Image
	//

	class _EXPORT_ CLImage : public CLMemory
	{
	protected:
		uvec3					_vTexDim;
		cl_image_format::type	_eFormat;
		
	protected:
		static bool s_DeconvertFormat(cl_image_format::type eFormat, ::cl_image_format &sFormat);
		static bool s_ConvertFormat(const ::cl_image_format &sFormat, cl_image_format::type &eFormat);

	public:
		CLImage();
		~CLImage();

		bool Create2D(const uvec2 &vDim, cl_memory::type eFlags, cl_image_format::type eFormat,
						void *pImage = nullptr, uint uRowPitch = 0);

		bool CreateTex2D(gl_texture::type eTarget, GLuint uTexture, cl_memory::type eFlags, uint uMipMap = 0);

		bool Create3D(const uvec3 &vDim, cl_memory::type eFlags, cl_image_format::type eFormat,
						void *pImage = nullptr, uint uRowPitch = 0, uint uSlicePitch = 0);

		bool CreateTex3D(gl_texture::type eTarget, GLuint uTexture, cl_memory::type eFlags, uint uMipMap = 0);

		bool CreateTex(const CTexturePtr &pGLTexture, cl_memory::type eFlags, uint uMipMap = 0,
					gl_texture::type eTarget = gl_texture::_UNKNOWN);

		bool CreateRB(GLuint uRenderBuffer, cl_memory::type eFlags);

		virtual void Destroy();
		
		bool EnqueueRead(CLQueue *pQueue, bool bASync, const svec3 &vOffset, const svec3 &vDataSize,
						const svec2 &vDataRowSlicePitch, void *pData,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueWrite(CLQueue *pQueue, bool bASync, const svec3 &vOffset, const svec3 &vDataSize,
						const svec2 &vDataRowSlicePitch, const void *pData,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueCopy(CLQueue *pQueue, CLImage *pSrcImage, const svec3 &vSrcOffset,
						const svec3 &vDstOffset, const svec3 &vSize,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueCopy(CLQueue *pQueue, CLBuffer *pSrcBuf, usize uSrcOffset, const svec3 &vDstOffset, const svec3 &vSize,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);
						
		bool EnqueueCopyToBuffer(CLQueue *pQueue, CLBuffer *pDstBuf, const svec3 &vSrcOffset,
						const svec3 &vSize, usize uDstOffset,
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool EnqueueMap(void *&pResult, svec2 &vRowSlicePitch, CLQueue *pQueue, bool bASync,
						e_rw_mode::type eRW, const svec3 &vOffset, const svec3 &vSize, 
						const cl_event_array_t &aEvents = cl_event_array_t(), CLEvent **pEvent = nullptr);

		bool					Is2D()			const	{ return _vTexDim.x != 0 && _vTexDim.y != 0 && _vTexDim.z == 0; }
		bool					Is3D()			const	{ return _vTexDim.x != 0 && _vTexDim.y != 0 && _vTexDim.z != 0; }
		const uvec3 &			GetDimension()	const	{ return _vTexDim; }
		cl_image_format::type	GetFormat()		const	{ return _eFormat; }
	};

//-------------------------------------------------------------------

}	// CLSystems
}	// Engine

#endif	// _UX_CL_MEMORY_H